<?php

    /*
        U方法，不仅能生成URL，还能生成上一个页面的URL，这个是TP不具备的
    */
    function url(){

    }

    /**
     * 单例模式创建对象
     * 这种方式显然只适用于不传递参数的创建对象。
     */
    function N($class){
        $class .='Controller';
        static $instances = array();
        if(isset($instances[$class])){
            return $instances[$class];
        }else{
            $newClass = new $class;
            $instances[$class] = $newClass;
            return $newClass;
        }
    }
    
    /**
     * 读取或设置语言
     */
    function L($name,$value=false){
        global $leaf;
        if($value==false){
            return isset($leaf['lang'][$name]) ? $leaf['lang'][$name] : false;
        }
    }

    /**
     * 读取或设置配置
     */
    function C($name,$value=false,$configKey=false){
        global $leaf;
        //如果是读取
        if($value===false && $configKey===false){
            return isset($leaf['config'][$name]) ? $leaf['config'][$name] : false;
        }else if( ($value!==false && $configKey===false) ){
            //如果是设置，且在应用中设置，没有第三个参数，则只影响到$leaf['config']的值
            $app = __APP__;
            empty($app) ? ($leaf['config'][$name] = $value) : ($leaf[$app][$name] = $value);
        }else if( ($value!==false && $configKey!==false) ){
            //如果是三个参数都有，则影响全局变量$leaf
            $leaf[$name] = $value;
        }
    }

    /**
     * 读取全局变量，可用GL('str.str1.str2')的形式来获取，最多支持4维，可自由拓展，使用前提是，你知道$leaf全局变量的数组结构
     */
    function GL($str){
        global $leaf;
        $exStr = explode('.', $str);
        $return = false;
        if( $count = count($exStr)<=3 ){
            switch ($count) {
                case 1:
                    $return = $leaf[$exStr[0]];
                    break;
                case 2:
                    $return = $leaf[$exStr[0]][$exStr[1]];
                    break;
                case 3:
                    $return = $leaf[$exStr[0]][$exStr[1]][$exStr[2]];
                    break;
                case 4:
                    $return = $leaf[$exStr[0]][$exStr[1]][$exStr[2]][$exStr[3]];
            }
        }else{
            $return = false;
        }
        return $return;
    }

    /**
     * 加载外部文件函数
     * 框架提示：该函数第一次调用的时候，是加载错误处理接口class.Error.php，若此时未加载，则错误并不交由框架处理
     * @param string $filename 要加载的文件
     * @param string $type 加载方式，默认为require
     * @param boolean $mode 加载失败时，是否报错
     * @param string $msg 加载失败时，报错的提示语
     * @return boolean 加载成功，返回true，否则返回false
     */
    function load($filename, $type='require', $mode=true, $msg=false){
        //判断文件是否存在，若存在，则依照相应的方式加载
        if(file_exists_case($filename)){
            switch ($type) {
                case 'include':
                    include $filename;
                    break;
                default:
                    require $filename;
                    break;
            }
            //加载计数+1
            addLoadedFile($filename);
            return true;
        }else{
            return false;
        }
    }

    /**
     * 错误处理调用函数，全局可用
     * 此函数让用户调用error产生的错误交由框架处理
     * @param $error_msg string 要输出的错误信息
     * @param $type int 制定的错误类型，0为致命错误，1为警告错误，2为notice错误
     * @param $type int 制定的错误的信息，数组类型，包括文件盒行号
     */
    function error($error_msg, $type=0, $outInfo=null){
        //若开发者传递$type有误，则按照致命错误处理
        if(!in_array($type, array(0,1,2))){
            $type=0;
        }
        $error_type=array(E_USER_ERROR,E_USER_WARNING,E_USER_NOTICE);
        trigger_error($error_msg,$error_type[$type]);
    }

    /**
     * 将已加载文件计数到全局变量$leaf中
     */
    function addLoadedFile($filename){
        global $leaf;
        if( is_array($filename) ){
            foreach ($filename as $key => $value) {
                $leaf['loadedFiles'][] = $value;
            }
        }else if( is_string($filename) ){
            $leaf['loadedFiles'][] = $filename;
        }
    }

    function is_utf8($string) {
        return preg_match('%^(?:
             [\x09\x0A\x0D\x20-\x7E]            # ASCII
           | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
           |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
           | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
           |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
           |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
           | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
           |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
       )*$%xs', $string);
    }
    
    /**
     * 优化格式的打印输出
     * @param string $var 变量
     * @param bool $return 是否return
     * @return mixed
     */
    function P($var, $return=false) {
        ob_start();
        var_dump($var);
        $output = ob_get_clean();
        if(!extension_loaded('xdebug')) {
            $output = preg_replace("/\]\=\>\n(\s+)/m", "] => ", $output);
            $output = '<pre style="text-align:left">'. htmlspecialchars($output, ENT_QUOTES). '</pre>';
        }
        if (!$return) {
            echo '<pre style="text-align:left">';
            echo($output);
            echo '</pre>';
        }else
            return $output;
    }
    
    /**
     * 发送常用http header信息
     * @param string $type
     */
    function send_http_header($type='utf8'){
        //utf8,html,wml,xml,图片、文档类型 等常用header
        switch($type){
            case 'utf8':
                header("Content-type: text/html; charset=utf-8");
                break;
            case 'xml':
                header("Content-type: text/xml; charset=utf-8");
                break;
        }
    }
    
    /**
     * 区分大小写的文件或目录存在判断
     * @param string $filename 文件明
     * @return bool
     */
    function file_exists_case($filename) {
        if(is_file($filename) || is_dir($filename)) {
            if( is_win() ) {
                if(basename(realpath($filename)) != basename($filename)){
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /**
     * 过滤gpc的特殊字符:'、"、<、>
     */
    function gpc_str_replace($str){
        return str_replace(array('<','>','"',"'",'%3C','%3E','%22','%27','%3c','%3e'), '', $str);
    }
    
    /**
     * 判断当前服务器是否为windows操作系统
     * @return bool
     */
    function is_win(){
        return strstr(PHP_OS, 'WIN') ? true : false ;
    }
    
    /**
     * 判断是否为cgi模式
     */
    function is_cgi(){
        return substr(PHP_SAPI, 0, 3)=='cgi' ? true : false ;
    }

    /**
     * 由值，获取值对应的b、kb、mb等单位
     * @param int $size 值
     */
    function unitConvert($size)
     {
        $unit=array('b','kb','mb','gb','tb','pb');
        return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
     }
    
    /**
     * 用于判断文件后缀是否是图片
     * @param string file 文件路径，通常是$_FILES['file']['tmp_name']
     * @return bool
     */
    function is_image_file($file){
        $fileextname = strtolower(substr(strrchr(rtrim(basename($file),'?'),"."),1,4));
        if(in_array($fileextname,array('jpg','jpeg','gif','png','bmp'))){
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * 用于判断文件后缀是否是PHP、EXE类的可执行文件
     * @param string file 文件路径
     * @return bool
     */
    function is_notsafe_file($file){
        $fileextname = strtolower(substr(strrchr(rtrim(basename($file),'?'), "."),1,4));
        if(in_array($fileextname,array('php','php3','php4','php5','exe','sh'))){
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * t函数用于过滤标签，输出没有html的干净的文本
     * @param string text 文本内容
     * @return string 处理后内容
     */
    function t($text){
        $text = nl2br($text);
        $text = real_strip_tags($text);
        $text = addslashes($text);
        $text = trim($text);
        return $text;
    }
    
    /**
     * h函数用于过滤不安全的html标签，输出安全的html
     * @param string $text 待过滤的字符串
     * @param string $type 保留的标签格式
     * @return string 处理后内容
     */
    function h($text, $type = 'html'){
        // 无标签格式
        $text_tags  = '';
        //只保留链接
        $link_tags  = '<a>';
        //只保留图片
        $image_tags = '<img>';
        //只存在字体样式
        $font_tags  = '<i><b><u><s><em><strong><font><big><small><sup><sub><bdo><h1><h2><h3><h4><h5><h6>';
        //标题摘要基本格式
        $base_tags  = $font_tags.'<p><br><hr><a><img><map><area><pre><code><q><blockquote><acronym><cite><ins><del><center><strike>';
        //兼容Form格式
        $form_tags  = $base_tags.'<form><input><textarea><button><select><optgroup><option><label><fieldset><legend>';
        //内容等允许HTML的格式
        $html_tags  = $base_tags.'<meta><ul><ol><li><dl><dd><dt><table><caption><td><th><tr><thead><tbody><tfoot><col><colgroup><div><span><object><embed><param>';
        //专题等全HTML格式
        $all_tags   = $form_tags.$html_tags.'<!DOCTYPE><html><head><title><body><base><basefont><script><noscript><applet><object><param><style><frame><frameset><noframes><iframe>';
        //过滤标签
        $text = real_strip_tags($text, ${$type.'_tags'});
        // 过滤攻击代码
        if($type != 'all') {
            // 过滤危险的属性，如：过滤on事件lang js
            while(preg_match('/(<[^><]+)(ondblclick|onclick|onload|onerror|unload|onmouseover|onmouseup|onmouseout|onmousedown|onkeydown|onkeypress|onkeyup|onblur|onchange|onfocus|action|background|codebase|dynsrc|lowsrc)([^><]*)/i',$text,$mat)){
                $text = str_ireplace($mat[0], $mat[1].$mat[3], $text);
            }
            while(preg_match('/(<[^><]+)(window\.|javascript:|js:|about:|file:|document\.|vbs:|cookie)([^><]*)/i',$text,$mat)){
                $text = str_ireplace($mat[0], $mat[1].$mat[3], $text);
            }
        }
        return $text;
    }
    
    /**
     * URL跳转函数
     * @param string $url ThinkSNS特有URL标识符
     * @param integer $time 跳转延时(秒)
     * @param string $msg 提示语
     * @return void
     */
    function redirect($url,$time=0,$msg='') {
        //多行URL地址支持
        $url = str_replace(array("\n", "\r"), '', $url);
        if(empty($msg))
            $msg    =   "系统将在{$time}秒之后自动跳转到{$url}！";
        if (!headers_sent()) {
            // redirect
            if(0===$time) {
                header("Location: ".$url);
            }else {
                header("Content-type: text/html; charset=utf-8");
                header("refresh:{$time};url={$url}");
                echo($msg);
            }
            exit();
        }else {
            $str    = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
            if($time!=0)
                $str   .=   $msg;
            exit($str);
        }
    }
    
    function mk_dir($dir, $mode = 0755){
        if (is_dir($dir) || @mkdir($dir,$mode)) return true;
        if (!mk_dir(dirname($dir),$mode)) return false;
        return @mkdir($dir,$mode);
    }
    
    /**
     * 获取客户端IP地址
     */
    function get_client_ip($type = 0) {
        $type       =  $type ? 1 : 0;
        static $ip  =   NULL;
        if ($ip !== NULL) return $ip[$type];
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos    =   array_search('unknown',$arr);
            if(false !== $pos) unset($arr[$pos]);
            $ip     =   trim($arr[0]);
        }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
            $ip     =   $_SERVER['HTTP_CLIENT_IP'];
        }elseif (isset($_SERVER['REMOTE_ADDR'])) {
            $ip     =   $_SERVER['REMOTE_ADDR'];
        }
        // IP地址合法验证
        $long = sprintf("%u",ip2long($ip));
        $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
        return $ip[$type];
    }
    
    
    
    /**
     * 获取字符串的长度
     *
     * 计算时, 汉字或全角字符占1个长度, 英文字符占0.5个长度
     *
     * @param string  $str
     * @param boolean $filter 是否过滤html标签
     * @return int 字符串的长度
     */
    function get_str_length($str, $filter = false){
        if ($filter) {
            $str = html_entity_decode($str, ENT_QUOTES);
            $str = strip_tags($str);
        }
        return (strlen($str) + mb_strlen($str, 'UTF8')) / 4;
    }
    
    /**
     * 自动转换字符集 支持数组转换
     * @param mixed  $fContents 待被转换的字符串或数组
     * @param string $from 源字符集
     * @param string $to 目标字符集
     * @return string 不能转换的话，直接返回原数组
     */
    function auto_charset($fContents,$from,$to){
        $from   =  strtoupper($from)=='UTF8'? 'utf-8':$from;
        $to       =  strtoupper($to)=='UTF8'? 'utf-8':$to;
        if( strtoupper($from) === strtoupper($to) || empty($fContents) || (is_scalar($fContents) && !is_string($fContents)) ){
            //如果编码相同或者非字符串标量则不转换
            return $fContents;
        }
        if(is_string($fContents) ) {
            if(function_exists('iconv')){
                return iconv($from,$to,$fContents);
            }else{
                return $fContents;
            }
        }
        elseif(is_array($fContents)){
            foreach ( $fContents as $key => $val ) {
                $_key =     auto_charset($key,$from,$to);
                $fContents[$_key] = auto_charset($val,$from,$to);
                if($key != $_key )
                    unset($fContents[$key]);
            }
            return $fContents;
        }
        else{
            return $fContents;
        }
    }
    
    /**
     * 加密函数
     * @param string $txt 被加密字符串
     * @param mixed $key 加密密钥，字符串或整型
     * @return string 返回加密之后的字符串
     */
    function jiami($txt, $key = '') {
        if(empty($key)){
            $key = 'key';
        }
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=_";
        $nh = rand ( 0, 64 );
        $ch = $chars [$nh];
        $mdKey = md5 ( $key . $ch );
        $mdKey = substr ( $mdKey, $nh % 8, $nh % 8 + 7 );
        $txt = base64_encode ( $txt );
        $tmp = '';
        $i = 0;
        $j = 0;
        $k = 0;
        for($i = 0; $i < strlen ( $txt ); $i ++) {
            $k = $k == strlen ( $mdKey ) ? 0 : $k;
            $j = ($nh + strpos ( $chars, $txt [$i] ) + ord ( $mdKey [$k ++] )) % 64;
            $tmp .= $chars [$j];
        }
        return $ch . $tmp;
    }
    
    /**
     * 解密函数
     * @param string $txt 被解密字符串
     * @param mixed $key 解密密钥，字符串或整型
     * @return string 返回解密之后的字符串
     */
    function jiemi($txt, $key = '') {
        if(empty($key)){
            $key = 'key';
        }
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-=_";
        $ch = $txt [0];
        $nh = strpos ( $chars, $ch );
        $mdKey = md5 ( $key . $ch );
        $mdKey = substr ( $mdKey, $nh % 8, $nh % 8 + 7 );
        $txt = substr ( $txt, 1 );
        $tmp = '';
        $i = 0;
        $j = 0;
        $k = 0;
        for($i = 0; $i < strlen ( $txt ); $i ++) {
            $k = $k == strlen ( $mdKey ) ? 0 : $k;
            $j = strpos ( $chars, $txt [$i] ) - $nh - ord ( $mdKey [$k ++] );
            while ( $j < 0 )
                $j += 64;
            $tmp .= $chars [$j];
        }
        return base64_decode ( $tmp );
    }